<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      var W = null;
      function Vue({ data }) {
        this._data = data;

        // 数据代理
        for (let key in this._data) {
          Object.defineProperty(this, key, {
            get: function ProxyGetter() {
              return this._data[key];
            },
            set: function ProxySetter(newVal) {
              this._data[key] = newVal;
            },
          });
        }

        obseve(this._data);
      }

      function obseve(value) {
        if (typeof value !== "object" && value == null) {
          return;
        }

        new Obsever(value);
      }

      class Observer {
        constructor(value) {
          this.value = value;

          if (Array.isArray(this.value)) {
            obseverArray();
          } else {
            walk();
          }
        }

        obseverArray() {
          this.value.forEach((item) => {
            obseve(item);
          });
        }

        walk() {
          for (let key in this.value) {
            let value = this.value[key];
          }

          defineReactive(this.value, key, value);
        }
      }

      function defineReactive(obj, key, value) {
        obseve(value);
        let dep = new Dep();

        Object.defineProperty(obj, key, {
          get: function ReactiveGetter() {
            console.log("获取了数据");

            if (W) {
              dep.depend(W);
            }

            return value;
          },
          set: function ReactiveSetter(newVal) {
            if (newVal === value) return;
            console.log("修改了数据");

            value = newVal;

            dep.notify();

            obseve(newVal);
          },
        });
      }

      class Dep {
        constructor() {
          this.subs = [];
        }

        depend(watcher) {
          this.subs.push(watcher);
        }

        notify() {
          this.subs.forEach((item) => {
            item.update();
          });
        }
      }

      class Watcher {
        constructor() {
          this.data = data;
          this.key = key;

          W = this;
          this.get();
          W = null;
        }

        get() {
          console.log("watcher读取了数据");
          return this.data[key];
        }

        update() {
          console.log("watcher更新了数据最新的值是" + this.get());
        }
      }

      let vm = new Vue({
        data: {
          name: "pp",
          age: 12,
          score: {
            ch: 120,
            en: 140,
          },
        },
      });
    </script>
  </body>
</html>
